package br.org.universa.sgos.persistencia.dao;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Collection;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
import javax.persistence.Query;

import br.org.universa.sgos.entidade.Entidade;

public abstract class DAOAbstrato<E extends Entidade> implements IDAOAbstrato<E> {
    private static EntityManagerFactory entityManagerFactory;
    private EntityManager entityManager;
    private Class<E> classePersistente;
    private final Type superClasseGenerica;
    private final ParameterizedType tipoParametrizado;

    /**
     * Contrutor que guarda o tipo atual da Classe T.
     */
    @SuppressWarnings("unchecked")
    public DAOAbstrato() {
        superClasseGenerica = getClass().getGenericSuperclass();
        tipoParametrizado = ((ParameterizedType) superClasseGenerica);
        setClassePersistente((Class<E>) tipoParametrizado.getActualTypeArguments()[0]);
    }

    private void setClassePersistente(Class<E> classePersistente) {
        this.classePersistente = classePersistente;
    }

    private Class<E> getClassePersistente() {
        return classePersistente;
    }

    @SuppressWarnings("unused")
    private Type getGenericSuperclass() {
        return superClasseGenerica;
    }

    @SuppressWarnings("unused")
    private ParameterizedType getParameterizedType() {
        return tipoParametrizado;
    }

    private static EntityManagerFactory getEntityManagerFactory() {
        if (entityManagerFactory == null) {
            entityManagerFactory = Persistence.createEntityManagerFactory("sgos-persistence");
        }
        return entityManagerFactory;
    }

    public void setEntityManager(EntityManager session) {
        this.entityManager = session;
    }

    public EntityManager getEntityManager() {
        if (entityManager == null) {
            entityManager = criarSession();
        }
        return entityManager;
    }

    public EntityManager criarSession() {
        return getEntityManagerFactory().createEntityManager();
    }

    public void finalizarSession() {
        getEntityManager().close();
        setEntityManager(null);
    }

    private EntityTransaction getTransacao() {
        return getEntityManager().getTransaction();
    }

    public void iniciarTransacao() {
        getTransacao().begin();
    }

    public void commit() {
        getTransacao().commit();
    }

    public void rollback() {
        getTransacao().rollback();
    }

    public static void inicializarSessionFactory() {
        getEntityManagerFactory();
    }

    @Override
    public void inserir(E entidade) {
        getEntityManager().persist(entidade);
    }

    @Override
    public void atualizar(E entidade) {
        getEntityManager().merge(entidade);
    }

    @Override
    public void excluir(E entidade) {
        getEntityManager().remove(entidade);

    }

    @Override
    public E obterPorId(Long id) {
        return getEntityManager().find(getClassePersistente(), id);
    }

    private String getHQLPadrao() {
        String nomeClassePersistenteComPacoteSemClass = getClassePersistente().toString().replace("class", " ");
        String hql = "from " + nomeClassePersistenteComPacoteSemClass;
        return hql;
    }

    @SuppressWarnings("unchecked")
    @Override
    public Collection<E> consultarTodos() {
        Query query = createQuery();
        return query.getResultList();
    }

    private Query createQuery() {
        Query query = getEntityManager().createQuery(getHQLPadrao());
        return query;
    }

}